[Submit] Fix regressions from the "Submit to my employer" flow (#94319)#96136
[Submit] Fix regressions from the "Submit to my employer" flow (#94319)#96136abzokhattab wants to merge 10 commits into
Conversation
Resolve the confirmation "To" name for a freshly created draft workspace (zero-workspace "Submit to my employer") via the policy explicitly passed to getPolicyName instead of broadening the early-bail guard with oldPolicyName, which affected all zero-policy users. The confirmation now forwards the draft policy for the matching participant so the name resolves through the normal path.
The track-expense details page menu still showed the single "Submit to someone" option. Split it into "Submit to a friend" / "Submit to my employer" behind the SUBMIT_2026 beta, matching the whisper (ChatActionableButtons). Fixes Expensify#96085.
moveTrackedExpenseToPolicy spread policyParams (which carries a full Onyx policy object for optimistic data) into the CategorizeTrackedExpense / AddTrackedExpenseToPolicy request. Non-Blob objects fail FormData serialization on Android, so the write failed and stamped "Unexpected error" on the expense preview. Fixes Expensify#96119.
Fall back to POLICY_DRAFTS when no real policy exists so callers that don't pass policyDraft (e.g. MoneyRequestConfirmationList) resolve a freshly created draft workspace. Fixes the sticky "Rate not valid" error (Expensify#96200) and the missing receipt empty state (Expensify#96214) in the zero-workspace "Submit to my employer" flow.
Add a confirmation guard so a tracked per diem expense can't be moved into a workspace without per diem support (e.g. a Submit workspace created via "Submit to my employer"). The submission previously fell through to a request the backend can't resolve, leaving the report stuck loading. Fixes Expensify#96212.
A draft-only report (the expense chat of a freshly created draft workspace) can't render as a report screen, so pre-inserting it stranded users on an infinite skeleton when backing out of "Submit to my employer" before submitting. Skip the REPORT_DRAFT fallback in the pre-insert readiness check. Fixes Expensify#96117.
…t policy name getPolicyName no longer bails to "Unavailable workspace" when the caller explicitly passes a policy, so getReportSections resolves the snapshot policy's real name for the expense report workspace avatar.
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
…aram Covers the branches Codecov flagged as uncovered: the new per diem moveExpensesError guard in useConfirmationValidation and the getPolicyName change that resolves an explicitly passed policy for draft workspaces.
|
@ZhenjaHorbach Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
|
The PR is ready for review @hungvu193 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50cf4ef91b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
garrettmknight
left a comment
There was a problem hiding this comment.
All this looks good from a product perspective and the changes match the behavior I'd expect.
|
Thanks, G! 👍 |
Explanation of Change
Follow-up to #94319 (Submit → "Submit to a friend" / "Submit to my employer"). This PR fixes the regressions reported against that PR, plus one targeted safety change:
1. Details page shows the two submit options (#96085)
The track-expense details page menu still rendered the single "Submit to someone" option, while the whisper (
ChatActionableButtons) already split it into "Submit to a friend" / "Submit to my employer". This mirrors that split on the details page, gated behind the sameSUBMIT_2026beta.2. "Unexpected error" after submitting to a new workspace (#96119)
moveTrackedExpenseToPolicyspreadpolicyParams— which carries a full Onyxpolicyobject used only for optimistic data — into theAddTrackedExpenseToPolicy/CategorizeTrackedExpenserequest. Non-Blob objects fail FormData serialization on Android, so the write failed, retried to exhaustion, and stamped the failure "Unexpected error" onto the expense preview. Thepolicyobject is now stripped from the API payload (it remains available for optimistic Onyx writes).3. Sticky "Rate not valid" error (#96200) and missing receipt empty state (#96214)
MoneyRequestConfirmationListre-derives its policy viausePolicyForTransactionwithout the draft policy, so in the zero-workspace "Submit to my employer" flow (destination is a draft workspace inPOLICY_DRAFTS)policyresolved toundefined. That broke rate validation (rates read fromundefined, so theinvalidRateerror could never clear) and hid the receipt empty state (isGroupPolicy(undefined)is false).usePolicyForTransactionnow falls back to the draft policy from Onyx; real policies always take precedence.4. Per diem submitted to a Submit workspace → infinite loading (#96212)
Per diem is a Control-plan feature, but nothing stopped a tracked per diem expense from being submitted into a workspace that can't process it. A confirmation guard now blocks it with the existing "You can't move per diem expenses…" error, mirroring the guard in
IOURequestEditReportCommon.5. Infinite skeleton when backing out of the confirmation page (#96117)
On narrow layouts the confirmation screen pre-inserts the destination report under the RHP. For the zero-workspace employer flow the destination is a draft-only report (
REPORT_DRAFT), which the report screen can't render — so the device back button revealed an infinite skeleton. The pre-insert readiness check now skips theREPORT_DRAFTfallback, leaving the origin self-DM under the RHP.6. Scope the draft-workspace name resolution to be targeted and safe (#92704 follow-up)
Replaces the broad
oldPolicyNameguard change ingetPolicyNamewith a targeted approach: honor thepolicyargument a caller explicitly passes, and forward the draft transaction policy for the matching participant inIOURequestStepConfirmation. This removes any behavior change for zero-policy users outside the beta.Fixed Issues
$ #96085
$ #96117
$ #96119
$ #96200
$ #96212
$ #96214
PROPOSAL:
Tests
Prerequisite: account with the
SUBMIT_2026beta, no workspaces, and a self DM.Details page options (#96085):
Back navigation (#96117):
Submit to new workspace (#96119, Android):
Receipt empty state (#96214):
Distance rate (#96200):
Per diem guard (#96212):
Offline tests
Same as tests — the fixes are client-side; the per diem guard and policy resolution work offline.
QA Steps
Same as tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Screen.Recording.2026-07-19.at.15.17.18.mov
Screen.Recording.2026-07-19.at.13.45.44.mov
Screen.Recording.2026-07-19.at.13.42.33.mov
Screen.Recording.2026-07-19.at.13.35.05.mov
Android: mWeb Chrome
iOS: Native
Screen.Recording.2026-07-19.at.16.06.23.mov
iOS: mWeb Safari
Screen.Recording.2026-07-19.at.16.09.50.mov
MacOS: Chrome / Safari
Screen.Recording.2026-07-19.at.13.11.51.mov
Screen.Recording.2026-07-19.at.15.54.01.mov
Screen.Recording.2026-07-19.at.15.21.23.mov